import pymysql
import requests
import json
import time
import hmac
import hashlib
import base64
import urllib.parse  # 新增：用于URL编码

# 数据库配置
DB_CONFIG = {
    'host': 'localhost',
    'user': 'root',
    'password': 'hui123456',
    'database': 'sms',
    'port': 3306,
    'charset': 'utf8mb4'
}

# 钉钉机器人配置（带加签）
# 请确保以下两个值正确无误
DINGTALK_ACCESS_TOKEN = 'd732fd45e91858a2f157493867dc8b86776952549453189e9754519183c17bcd'  # 仅token部分
DINGTALK_SECRET = 'SECd164829922391a2a3d241ed2a017bc97178d101dc70c9b55eb60a35a02783fbc'  # 加签密钥

# 记录最后处理的短信ID，避免重复发送
LAST_PROCESSED_ID = 0

def get_sign(timestamp, secret):
    """生成钉钉加签签名（修复版）"""
    # 1. 拼接timestamp和secret，注意是"\n"分隔
    string_to_sign = f"{timestamp}\n{secret}"
    
    # 2. 使用HMAC-SHA256计算签名
    hmac_code = hmac.new(
        secret.encode('utf-8'),  # 密钥
        string_to_sign.encode('utf-8'),  # 待加密字符串
        digestmod=hashlib.sha256
    ).digest()
    
    # 3. 进行Base64编码后再URL编码
    sign = urllib.parse.quote_plus(base64.b64encode(hmac_code).decode('utf-8'))
    return sign

def get_dingtalk_url():
    """生成带加签的钉钉Webhook URL（修复版）"""
    # 获取当前毫秒级时间戳
    timestamp = str(round(time.time() * 1000))
    # 生成签名
    sign = get_sign(timestamp, DINGTALK_SECRET)
    
    # 拼接完整URL（包含所有必要参数）
    url = f"https://oapi.dingtalk.com/robot/send?access_token={DINGTALK_ACCESS_TOKEN}&timestamp={timestamp}&sign={sign}"
    print(f"生成的请求URL: {url}")  # 调试用，可查看生成的URL
    return url

def get_db_connection():
    """建立数据库连接"""
    try:
        conn = pymysql.connect(
            host=DB_CONFIG['host'],
            user=DB_CONFIG['user'],
            password=DB_CONFIG['password'],
            database=DB_CONFIG['database'],
            port=DB_CONFIG['port'],
            charset=DB_CONFIG['charset']
        )
        return conn
    except Exception as e:
        print(f"数据库连接失败: {str(e)}")
        return None

def get_latest_sms():
    """获取数据库中最新的一条未处理的短信"""
    global LAST_PROCESSED_ID
    conn = get_db_connection()
    if not conn:
        return None
    
    try:
        with conn.cursor(pymysql.cursors.DictCursor) as cursor:
            sql = """
            SELECT * FROM received_sms 
            WHERE id > %s 
            ORDER BY id DESC 
            LIMIT 1
            """
            cursor.execute(sql, (LAST_PROCESSED_ID,))
            result = cursor.fetchone()
            
            if result:
                LAST_PROCESSED_ID = result['id']
                return result
            return None
    except Exception as e:
        print(f"查询数据库失败: {str(e)}")
        return None
    finally:
        if conn:
            conn.close()

def send_to_dingtalk(sms_data):
    """将短信数据发送到钉钉（带加签验证）"""
    if not sms_data:
        return False
        
    # 格式化消息内容（确保包含自定义关键词，如果设置了的话）
    message = f"新收到短信 📱\n发送者: {sms_data['sender']}\n时间: {sms_data['receive_time'] or sms_data['create_time']}\n内容: {sms_data['content']}"
    
    # 钉钉消息格式
    data = {
        "msgtype": "text",
        "text": {
            "content": message
        }
    }
    
    try:
        # 获取带加签的URL
        url = get_dingtalk_url()
        
        response = requests.post(
            url,
            headers={"Content-Type": "application/json"},
            data=json.dumps(data)
        )
        
        print(f"钉钉响应: {response.text}")  # 调试用，查看完整响应
        result = response.json()
        
        if result.get('errcode') == 0:
            print(f"成功发送到钉钉: {sms_data['id']}")
            return True
        else:
            print(f"发送到钉钉失败: {result.get('errmsg')}")
            return False
    except Exception as e:
        print(f"发送请求失败: {str(e)}")
        return False

def run_monitor(interval=10):
    """运行监控程序，定时检查新短信"""
    print(f"开始监控短信，每{interval}秒检查一次...")
    print(f"当前最后处理的短信ID: {LAST_PROCESSED_ID}")
    
    try:
        while True:
            latest_sms = get_latest_sms()
            
            if latest_sms:
                print(f"发现新短信: ID={latest_sms['id']}, 发送者={latest_sms['sender']}")
                send_to_dingtalk(latest_sms)
                
            time.sleep(interval)
    except KeyboardInterrupt:
        print("\n程序已手动停止")
    except Exception as e:
        print(f"程序运行出错: {str(e)}")

if __name__ == "__main__":
    run_monitor(interval=10)
